/*
 * Copyright (c) 2018, apexes.net. All rights reserved.
 *
 *         http://www.apexes.net
 *
 */
package net.apexes.commons.lang;

/**
 * @author <a href=mailto:hedyn@foxmail.com>HeDYn</a>
 */
public final class CRCs {
    private CRCs() {}

    /**
     * 计算数组的CRC8校验值
     *
     * @param bytes 需要计算的数组
     * @return CRC8校验值
     */
    public static byte crc8(byte[] bytes) {
        return crc8(bytes, 0, bytes.length, (byte) 0);
    }

    /**
     * 计算CRC8校验值
     *
     * @param bytes   数据
     * @param offset 起始位置
     * @param len    长度
     * @return 校验值
     */
    public static byte crc8(byte[] bytes, int offset, int len) {
        return crc8(bytes, offset, len, (byte) 0);
    }

    /**
     * 计算CRC8校验值
     *
     * @param bytes   数据
     * @param offset 起始位置
     * @param len    长度
     * @param preval 之前的校验值
     * @return 校验值
     */
    public static byte crc8(byte[] bytes, int offset, int len, byte preval) {
        byte ret = preval;
        for (int i = offset; i < (offset + len); ++i) {
            ret = CRC8_TAB[(0x00ff & (ret ^ bytes[i]))];
        }
        return ret;
    }

    /**
     * 计算CRC16校验
     *
     * @param bytes
     *            需要计算的数组
     * @return CRC16校验值
     */
    public static int crc16(byte[] bytes) {
        return crc16(bytes, 0, bytes.length);
    }

    /**
     * 计算CRC16校验
     *
     * @param bytes
     *            需要计算的数组
     * @param offset
     *            起始位置
     * @param len
     *            长度
     * @return CRC16校验值
     */
    public static int crc16(byte[] bytes, int offset, int len) {
        return crc16(bytes, offset, len, 0xffff);
    }

    /**
     * 计算CRC16校验
     *
     * @param bytes
     *            需要计算的数组
     * @param offset
     *            起始位置
     * @param len
     *            长度
     * @param preval
     *            之前的校验值
     * @return CRC16校验值
     */
    public static int crc16(byte[] bytes, int offset, int len, int preval) {
        int ucCRCHi = (preval & 0xff00) >> 8;
        int ucCRCLo = preval & 0x00ff;
        int iIndex;
        for (int i = 0; i < len; ++i) {
            iIndex = (ucCRCLo ^ bytes[offset + i]) & 0x00ff;
            ucCRCLo = ucCRCHi ^ CRC16_TAB_H[iIndex];
            ucCRCHi = CRC16_TAB_L[iIndex];
        }
        return ((ucCRCHi & 0x00ff) << 8) | (ucCRCLo & 0x00ff) & 0xffff;
    }

    private static final byte[] CRC8_TAB = {
            (byte) 0,   (byte) 94,  (byte) 188, (byte) 226, (byte) 97,  (byte) 63,  (byte) 221, (byte) 131,
            (byte) 194, (byte) 156, (byte) 126, (byte) 32,  (byte) 163, (byte) 253, (byte) 31,  (byte) 65,
            (byte) 157, (byte) 195, (byte) 33,  (byte) 127, (byte) 252, (byte) 162, (byte) 64,  (byte) 30,
            (byte) 95,  (byte) 1,   (byte) 227, (byte) 189, (byte) 62,  (byte) 96,  (byte) 130, (byte) 220,
            (byte) 35,  (byte) 125, (byte) 159, (byte) 193, (byte) 66,  (byte) 28,  (byte) 254, (byte) 160,
            (byte) 225, (byte) 191, (byte) 93,  (byte) 3,   (byte) 128, (byte) 222, (byte) 60,  (byte) 98,
            (byte) 190, (byte) 224, (byte) 2,   (byte) 92,  (byte) 223, (byte) 129, (byte) 99,  (byte) 61,
            (byte) 124, (byte) 34,  (byte) 192, (byte) 158, (byte) 29,  (byte) 67,  (byte) 161, (byte) 255,
            (byte) 70,  (byte) 24,  (byte) 250, (byte) 164, (byte) 39,  (byte) 121, (byte) 155, (byte) 197,
            (byte) 132, (byte) 218, (byte) 56,  (byte) 102, (byte) 229, (byte) 187, (byte) 89,  (byte) 7,
            (byte) 219, (byte) 133, (byte) 103, (byte) 57,  (byte) 186, (byte) 228, (byte) 6,   (byte) 88,
            (byte) 25,  (byte) 71,  (byte) 165, (byte) 251, (byte) 120, (byte) 38,  (byte) 196, (byte) 154,
            (byte) 101, (byte) 59,  (byte) 217, (byte) 135, (byte) 4,   (byte) 90,  (byte) 184, (byte) 230,
            (byte) 167, (byte) 249, (byte) 27,  (byte) 69,  (byte) 198, (byte) 152, (byte) 122, (byte) 36,
            (byte) 248, (byte) 166, (byte) 68,  (byte) 26,  (byte) 153, (byte) 199, (byte) 37,  (byte) 123,
            (byte) 58,  (byte) 100, (byte) 134, (byte) 216, (byte) 91,  (byte) 5,   (byte) 231, (byte) 185,
            (byte) 140, (byte) 210, (byte) 48,  (byte) 110, (byte) 237, (byte) 179, (byte) 81,  (byte) 15,
            (byte) 78,  (byte) 16,  (byte) 242, (byte) 172, (byte) 47,  (byte) 113, (byte) 147, (byte) 205,
            (byte) 17,  (byte) 79,  (byte) 173, (byte) 243, (byte) 112, (byte) 46,  (byte) 204, (byte) 146,
            (byte) 211, (byte) 141, (byte) 111, (byte) 49,  (byte) 178, (byte) 236, (byte) 14,  (byte) 80,
            (byte) 175, (byte) 241, (byte) 19,  (byte) 77,  (byte) 206, (byte) 144, (byte) 114, (byte) 44,
            (byte) 109, (byte) 51,  (byte) 209, (byte) 143, (byte) 12,  (byte) 82,  (byte) 176, (byte) 238,
            (byte) 50,  (byte) 108, (byte) 142, (byte) 208, (byte) 83,  (byte) 13,  (byte) 239, (byte) 177,
            (byte) 240, (byte) 174, (byte) 76,  (byte) 18,  (byte) 145, (byte) 207, (byte) 45,  (byte) 115,
            (byte) 202, (byte) 148, (byte) 118, (byte) 40,  (byte) 171, (byte) 245, (byte) 23,  (byte) 73,
            (byte) 8,   (byte) 86,  (byte) 180, (byte) 234, (byte) 105, (byte) 55,  (byte) 213, (byte) 139,
            (byte) 87,  (byte) 9,   (byte) 235, (byte) 181, (byte) 54,  (byte) 104, (byte) 138, (byte) 212,
            (byte) 149, (byte) 203, (byte) 41,  (byte) 119, (byte) 244, (byte) 170, (byte) 72,  (byte) 22,
            (byte) 233, (byte) 183, (byte) 85,  (byte) 11,  (byte) 136, (byte) 214, (byte) 52,  (byte) 106,
            (byte) 43,  (byte) 117, (byte) 151, (byte) 201, (byte) 74,  (byte) 20,  (byte) 246, (byte) 168,
            (byte) 116, (byte) 42,  (byte) 200, (byte) 150, (byte) 21,  (byte) 75,  (byte) 169, (byte) 247,
            (byte) 182, (byte) 232, (byte) 10,  (byte) 84,  (byte) 215, (byte) 137, (byte) 107, (byte) 53
    };

    private static final byte[] CRC16_TAB_H = {
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40
    };

    private static final byte[] CRC16_TAB_L = {
            (byte) 0x00, (byte) 0xC0, (byte) 0xC1, (byte) 0x01, (byte) 0xC3, (byte) 0x03, (byte) 0x02, (byte) 0xC2,
            (byte) 0xC6, (byte) 0x06, (byte) 0x07, (byte) 0xC7, (byte) 0x05, (byte) 0xC5, (byte) 0xC4, (byte) 0x04,
            (byte) 0xCC, (byte) 0x0C, (byte) 0x0D, (byte) 0xCD, (byte) 0x0F, (byte) 0xCF, (byte) 0xCE, (byte) 0x0E,
            (byte) 0x0A, (byte) 0xCA, (byte) 0xCB, (byte) 0x0B, (byte) 0xC9, (byte) 0x09, (byte) 0x08, (byte) 0xC8,
            (byte) 0xD8, (byte) 0x18, (byte) 0x19, (byte) 0xD9, (byte) 0x1B, (byte) 0xDB, (byte) 0xDA, (byte) 0x1A,
            (byte) 0x1E, (byte) 0xDE, (byte) 0xDF, (byte) 0x1F, (byte) 0xDD, (byte) 0x1D, (byte) 0x1C, (byte) 0xDC,
            (byte) 0x14, (byte) 0xD4, (byte) 0xD5, (byte) 0x15, (byte) 0xD7, (byte) 0x17, (byte) 0x16, (byte) 0xD6,
            (byte) 0xD2, (byte) 0x12, (byte) 0x13, (byte) 0xD3, (byte) 0x11, (byte) 0xD1, (byte) 0xD0, (byte) 0x10,
            (byte) 0xF0, (byte) 0x30, (byte) 0x31, (byte) 0xF1, (byte) 0x33, (byte) 0xF3, (byte) 0xF2, (byte) 0x32,
            (byte) 0x36, (byte) 0xF6, (byte) 0xF7, (byte) 0x37, (byte) 0xF5, (byte) 0x35, (byte) 0x34, (byte) 0xF4,
            (byte) 0x3C, (byte) 0xFC, (byte) 0xFD, (byte) 0x3D, (byte) 0xFF, (byte) 0x3F, (byte) 0x3E, (byte) 0xFE,
            (byte) 0xFA, (byte) 0x3A, (byte) 0x3B, (byte) 0xFB, (byte) 0x39, (byte) 0xF9, (byte) 0xF8, (byte) 0x38,
            (byte) 0x28, (byte) 0xE8, (byte) 0xE9, (byte) 0x29, (byte) 0xEB, (byte) 0x2B, (byte) 0x2A, (byte) 0xEA,
            (byte) 0xEE, (byte) 0x2E, (byte) 0x2F, (byte) 0xEF, (byte) 0x2D, (byte) 0xED, (byte) 0xEC, (byte) 0x2C,
            (byte) 0xE4, (byte) 0x24, (byte) 0x25, (byte) 0xE5, (byte) 0x27, (byte) 0xE7, (byte) 0xE6, (byte) 0x26,
            (byte) 0x22, (byte) 0xE2, (byte) 0xE3, (byte) 0x23, (byte) 0xE1, (byte) 0x21, (byte) 0x20, (byte) 0xE0,
            (byte) 0xA0, (byte) 0x60, (byte) 0x61, (byte) 0xA1, (byte) 0x63, (byte) 0xA3, (byte) 0xA2, (byte) 0x62,
            (byte) 0x66, (byte) 0xA6, (byte) 0xA7, (byte) 0x67, (byte) 0xA5, (byte) 0x65, (byte) 0x64, (byte) 0xA4,
            (byte) 0x6C, (byte) 0xAC, (byte) 0xAD, (byte) 0x6D, (byte) 0xAF, (byte) 0x6F, (byte) 0x6E, (byte) 0xAE,
            (byte) 0xAA, (byte) 0x6A, (byte) 0x6B, (byte) 0xAB, (byte) 0x69, (byte) 0xA9, (byte) 0xA8, (byte) 0x68,
            (byte) 0x78, (byte) 0xB8, (byte) 0xB9, (byte) 0x79, (byte) 0xBB, (byte) 0x7B, (byte) 0x7A, (byte) 0xBA,
            (byte) 0xBE, (byte) 0x7E, (byte) 0x7F, (byte) 0xBF, (byte) 0x7D, (byte) 0xBD, (byte) 0xBC, (byte) 0x7C,
            (byte) 0xB4, (byte) 0x74, (byte) 0x75, (byte) 0xB5, (byte) 0x77, (byte) 0xB7, (byte) 0xB6, (byte) 0x76,
            (byte) 0x72, (byte) 0xB2, (byte) 0xB3, (byte) 0x73, (byte) 0xB1, (byte) 0x71, (byte) 0x70, (byte) 0xB0,
            (byte) 0x50, (byte) 0x90, (byte) 0x91, (byte) 0x51, (byte) 0x93, (byte) 0x53, (byte) 0x52, (byte) 0x92,
            (byte) 0x96, (byte) 0x56, (byte) 0x57, (byte) 0x97, (byte) 0x55, (byte) 0x95, (byte) 0x94, (byte) 0x54,
            (byte) 0x9C, (byte) 0x5C, (byte) 0x5D, (byte) 0x9D, (byte) 0x5F, (byte) 0x9F, (byte) 0x9E, (byte) 0x5E,
            (byte) 0x5A, (byte) 0x9A, (byte) 0x9B, (byte) 0x5B, (byte) 0x99, (byte) 0x59, (byte) 0x58, (byte) 0x98,
            (byte) 0x88, (byte) 0x48, (byte) 0x49, (byte) 0x89, (byte) 0x4B, (byte) 0x8B, (byte) 0x8A, (byte) 0x4A,
            (byte) 0x4E, (byte) 0x8E, (byte) 0x8F, (byte) 0x4F, (byte) 0x8D, (byte) 0x4D, (byte) 0x4C, (byte) 0x8C,
            (byte) 0x44, (byte) 0x84, (byte) 0x85, (byte) 0x45, (byte) 0x87, (byte) 0x47, (byte) 0x46, (byte) 0x86,
            (byte) 0x82, (byte) 0x42, (byte) 0x43, (byte) 0x83, (byte) 0x41, (byte) 0x81, (byte) 0x80, (byte) 0x40
    };

}
